package com.zyj.benchmark.sample;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.concurrent.TimeUnit;

/**
 * 这个例子展示了一种场景: 有些代码会被JVM优化掉, 使得基准测试结果不准确
 * ---
 * baseline(): 空方法
 * measureWrong(): 由于计算结果并没有返回, JVM会自动优化, 使其耗时测得与baseLine()一样
 * measureRight(): 将计算结果返回了, JVM不会自动优化, 这样才能真正测得真实的执行效率
 */
@Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class Sample_08_DeadCode {

    private double x = Math.PI; //π

    private double compute(double d) {
        for (int c = 0; c < 10; c++) {
            d = d * d / Math.PI;
        }
        return d;
    }

    @Benchmark
    public void baseline() {
        // do nothing, this is a baseline
    }

    //错误的例子, 这个方法会被JIT优化成空方法
    @Benchmark
    public void measureWrong() {
        compute(x);  //因为我们没有使用计算结果, JVM会直接把这段代码优化掉, 相当于基准测试了个空方法
    }

    @Benchmark
    public double measureRight() {
        //正确的做法, 把结果返回, 让JVM认为计算不能省略
        return compute(x);
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(Sample_08_DeadCode.class.getSimpleName())
                .forks(1)
                .jvmArgs("-server") //注意这里一定要设置server模式, 以充分利用JIT
                .build();

        new Runner(opt).run();
    }
}
